import React from 'react';
import classNames from 'classnames';
import Input from '../Input';


class Form extends React.Component {
    displayName = 'Form';

    constructor (props) {
        super(props);
        const pojoProps = props.pojo || {};
        this.state = {
            id: 1,
            pojo: pojoProps
        };

        this.injectSetPojoProps();
    }

    items = {};

    injectSetPojoProps () {
        const pojo = this.state.pojo;
        const attrs = Object.keys(pojo);
        attrs.forEach(attr => {
            const name = attr.substr(0, 1).toUpperCase() + attr.substr(1);
            this[`set${name}`] = this.setProps.bind(this, attr);
        });
    }

    setProps = (field, v) => {
        const po = this.state.pojo;
        po[field] = v;
        this.setState({
            id: this.state.id + 1,
            pojo: po
        });
    }

    _update () {
        this.setState({
            id: this.state.id + 1
        });
    }

    async isValid () {
        const po = this.state.pojo;
        for (const name in this.items) {
            const control = this.items[name];
            if (!await control._check(po[name])) {
                return false;
            }
        }

        return true;
    }

    getFormParams () {
        return this.state.pojo;
    }

    onSubmit = (event) => {
        event.preventDefault();
        if (this.beforeSubmit) {
            return this.beforeSubmit();
        }
        return false;
    }

    onChangeProps = (field, v) => {
        const pojo = this.state.pojo;
        pojo[field] = v;

        this.setState({
            pojo
        });
    }

    /**
     * 将子元素绑定到表单
     * @method itemBind
     * @param data 子元素数据
     */
    itemBind = (item, name) => {
        if (name) {
            this.items[name] = item;
        } else {
            console.info('FormItem need a name property');
        }
    }

    /**
     * 将子元素从表单中解绑
     * @method itemUnBind
     * @param name
     */
    itemUnBind = (name) => {
        delete this.items[name];
    }

    renderChildren (ele) {
        ele = ele || this;
        const pojo = this.state.pojo;
        return React.Children.map(ele.props.children, (child) => {
            const componentName = (child && child.type && child.type.displayName) ? child.type.displayName : '';
            if (componentName === 'FormItem') {
                const props = Object.assign({
                    key: `${child.props.name}_${this.state.id}`,
                    itemBind: this.itemBind,
                    itemUnBind: this.itemUnBind,
                    pojo
                }, child.props);
                props.gutter = props.gutter !== undefined ? props.gutter : this.props.gutter;
                props.layout = props.layout !== undefined ? props.layout : this.props.layout;
                props.size = props.size !== undefined ? props.size : this.props.size;
                props.labelWidth = props.labelWidth !== undefined ? props.labelWidth : this.props.labelWidth;

                const changeHandler = props.onChange || function () {};
                const scope = this;
                props.onChange = function () {
                    const args = Array.prototype.slice.call(arguments);
                    changeHandler.apply(this, args);
                    const newProps = [props.name].concat(args);
                    scope.onChangeProps.call(scope, ...newProps);
                };

                if (componentName === 'FormItem') {
                    props.value = pojo ? pojo[props.name] : props.value;
                    if (props.value !== undefined && props.value !== null) {
                        if (typeof props.value !== 'object' && typeof props.value !== 'boolean') {
                            props.value = `${props.value}`;
                        }
                    } else {
                        props.value = '';
                    }
                }
                return React.cloneElement(child, props);
            } else {
                if (child && child.props && child.props.children) {
                    return React.cloneElement(child, child.props, this.renderChildren(child));
                }   else {
                    return child;
                }
            }
        });
    }

    render () {
        const {pojo} = this.state;
        let {component, className, style, encType, action, method, target, layout} = this.props;
        const clazzName = classNames('cm-form', className, {
            [`cm-form-${layout}`]: layout
        });
        component = component || 'form';
        const formProps = component === 'div' ? {} : {
            encType,
            action,
            method,
            target,
            onSubmit: this.onSubmit
        };
        const ps = Object.assign({
            ref: f => this.form = f,
            className: clazzName,
            style
        }, formProps);
        return React.createElement(component, ps, this.renderChildren());
    }
}

export default Form;
